|
Obfuscator
|
T o o l s
-Obfuscator
-Installer
-Assembler
-Links
-Old tools
|
| |
Hashjava
contains a java library and two applications which
obfuscate and shrink your class files. Hashjava runs on
Java 1.0.2 and 1.1 compliant VMs, and handles Java 1.0.2 and 1.1
class files.
Using hashjava on your applets does not make it safe from
decompilation, it just takes a little longer to make sense of
it. Please use version 0.8 released on September 4, 1997,
which fixes some bugs handling inner classes and handles code coverage
attributes inserted by the JDK compiler.
|
 |
- Download a self extracting class
file. Save this file as hjinstall.class and run
"java hjinstall". If you have problems installing
this program with its GUI, try installing it in console mode, with
"java hjinstall -o path/to/destination".
|
| |
contents
|
| |
|
| |
applet obfuscator |
| |
Hashjava includes an
example application which obfuscates applets. If the installation
in the previous step was successful, you should find a script
in the distribution as bin/HashApplet. If for any
reason this file was not created, the application main class
is sbktech.tools.hashjava.hashpplet.Main.
The wizard will guide you through the steps to obfuscate your
applet. The idea is to feed it a URL to an html file with your
original applet, and an output directory to write out the obfuscated applet.
You can select the types of symbols to obfuscate (class names,
method names, field names), how you want to handle debugging symbols
(keep, remove or put confusing information in them) or select the obfuscated
names (lowercase English alphabets, numbers or all valid java unicode
characters.)
Play it safe! Back up your applets before using this
application.
Start the application by running
% bin/HashApplet
This will launch a session which you can guide to load,
obfuscate and write out applets from an HTML
file. If the obfuscation was successful, you will find a copy of
the original HTML file and obfuscated bytecode
in the output directory.
| Watch out for these problems! |
- HashApplet does not detect images or other files that are
explicitly loaded by the applet, so you will have to copy
such files to make the obfuscated applet work again.
- Some sequences of html can confuse HashApplet. If HashApplet
incorrectly detects no applet tags in the HTML source, try using a
simpler HTML file with just a set of applet tags.
- HashApplet tries to duplicate the original directory
structure of applets which use CODEBASE tags, but some
combinations can defeat it. In particular, using a CODEBASE
with an absolute URL will usually result in an incorrect directory
structure.
- If any classes are shared between applets which haven't
been obfuscated at the same time, some applets will be incorrectly
obfuscated. Obfuscate all applets at the same time --
create a single dummy html file with references to all
your applets and run HashApplet on that file.
- Stack traces will no longer be available. To preserve stack
traces (but lose some obfuscation) retain source file names
and line numbers.
- If your code uses Class.forName(), HashApplet will
incorrectly or incompletely obfuscate the bytecode. HashApplet
will notify you when obfuscated classes use this call.
You should turn off renaming class names, which correctly,
but incompletely obfuscates the bytecode. To obfuscate all the
bytecode, create a single dummy html file with references to all of
your classes called through forName() (even if they don't
subclass Applet) and run HashApplet on this file. You
should still turn off renaming classes.
|
|
| |
command line obfuscator
|
| |
Hashjava also includes a command line obfuscator
which uses a configuration file to provide a greater degree of control over
what methods and classes get renamed.
Start the command line obfuscator with a configuration file
as its only argument.
% bin/Hashjava <path To Configuration File>
The minimum things to include in a configuration file are the
root directory (or zip file) of a set of classes to obfuscate, and
an output directory to store the obfuscated classes.
ObfuscateRoot("/path/to/original/classes");
OutputDir("/path/to/new/classes");
|
With just this information, every class recursively found from the
original directory will be fully obfuscated. Every method and field
that can be renamed will be renamed, and the obfuscated classes will
be placed into the new directory.
You can now selectively prevent an entire class, or selected methods
or fields, or just the class name from being obfuscated. For instance,
ObfuscateRoot("/path/to/original/classes");
OutputDir("/path/to/new/classes");
ExcludeAll(PUBLIC, "MyMainClass");
|
will fully obfuscate all classes except
MyMainClass. You can refine this further and just
keep the class name and the main() method name for
MyMainClass with
ObfuscateRoot("/path/to/original/classes");
OutputDir("/path/to/new/classes");
ExcludeClass(PUBLIC, "MyMainClass");
ExcludeMethod(PUBLIC & STATIC,
"MyMainClass.main");
|
You can also specify wildcards in the string.
Please refer to the example configuration
file in the distribution which uses all the directives understood
by the batch obfuscator.
|
| |
HashApplet and mocha
|
| |
Mocha
is a popular freely available decompiler.
Mocha's author also provides an obfuscator
Crema, which however is not freely available if you want to obfuscate applets.
The free version of Crema inserts illegal identifiers in applets
which does not pass security checks in many browsers.
Hanpeter, the author of Mocha and Crema has passed away.
By default, HashApplet inserts a few confusing debugging
attributes (this does not affect the applet unless it runs
under a debugger) which consistently seems to crash mocha.
If you change the settings to instead remove all debugging attributes,
mocha appears to work again.
Here is mocha output on part of a class from one of the
JDK demos before and after using HashApplet.
| Mocha before HashApplet |
void transform()
{
if (transformed || nvert <= 0)
return;
if (tvert == null || tvert.length < nvert * 3)
tvert = new int[nvert * 3];
mat.transform(vert, tvert, nvert);
transformed = true;
}
|
| After HashApplet (without mocha bomb) |
void C()
{
if (I || E <= 0)
return;
if (C == null || C.length < E * 3)
C = new int[E * 3];
J.O(A, C, E);
I = true;
}
|
|
| |
programming with hashjava
|
| |
Hashjava is really just a
library to fix up references in a set of bytecode files as you alter
symbol names in any of them. The
hashjava
API lets you add a set of classes and examine and alter symbols
in them.
| Obfuscation works in 3 steps |
- Add all classes to be kept in sync.
- Alter desired symbols in each class.
- Write out the altered classes.
|
The Environment
stores information about all the classes. It delegates the
reading/writing of classes, and the chore of picking new symbol names to
its instantiator.
So to create an Environment, you have to hand it an instance of the
BytecodeFactory
and the
Obfuscator
interfaces.
You actually have to pass an instance of the
Statistics
interface as well, which effectively observes the state of
the Environment.
The distribution includes
Example.java
under the hashjava/src directory. This is a small application
which demonstrates how to use the library.
Once you create an Environment, obfuscation works in three stages.
- Add all the bytecode with the
addClass()
method. The Environment will automatically add any dependent classes
(which are the superclasses or interfaces implemented by the class)
using your BytecodeFactory interface. You can optionally ask
for all dependencies to be loaded, which means any class
referenced in the bytecode will be automatically added.
- Obfuscate the bytecode with the
obfuscate()
method. This calls your
Obfuscator interface with every class in the environment.
You can use the methods in
ClassInfo
to examine and alter symbols in each class.
- Write out the altered bytecode with the
dump()
method.
|
| |
frequently asked questions
|
| |
- I get an OutOfMemoryError running the obfuscator
- Edit the scripts and try increasing the size of the virtual
machine heap space. For the Sun JDK, use the command line option
-mx 80m for example, to use 80 MB of heap space.
- How do I obfuscate a netscape IFC applet?
- Increase the default heap size, because
obfuscating an IFC applet needs a lot of memory. If
you write a "typical" IFC applet, it probably uses a Class.forName()
call to load the real applet, which needs to be handled properly. One
solution is to use
a special html file used only for obfuscation, which contains
a fake applet tag pointing to the class for your real IFC applet. For
example, the original HTML file for the Aquarium demo looks like
<applet code="NetscapeApplet"
width=640 height=410>
<param name="ApplicationClass"
value="Aquarium">
</applet>
and the special html file used only for obfuscation looks like
<applet code="NetscapeApplet"
width=640 height=410>
<param name="ApplicationClass"
value="Aquarium">
</applet>
<applet code=Aquarium
width=10 height=10>
</applet>
An alternate solution is to use the command line
obfuscator. Here is a sample configuration file, again for the
Aquarium demo from the IFC demo.
ObfuscateRoot
("/cadmium4/examples/Aquarium");
OutputDir
("/tmp/newAquarium");
ExcludeAll
(ALL, "netscape.*");
ExcludeClass
(ALL, "NetscapeApplet");
ExcludeClass
(ALL, "Aquarium");
DontDump
(ALL, "netscape.*");
|
- How do I change the names chosen by the obfuscator?
- If you want to specify an explicit map of original names to obfuscated
names, use the LoadMap directive in the configuration
file for the command line obfuscator.
This reads in an ASCII file where each line is an entry like
ClassName=NewName
ClassName.method=newMethodName
If the batch obfuscator does not find a name for some class or method
or field here, it picks a random name, and is guaranteed not to conflict
with any name you have used in the LoadMap file.
If you want to specify your own algorithm to map names, write a java
class which implements the
NameGenerator interface.
Specify this class name in any of the
ClassNameGenerator, FieldNameGenerator or
MethodNameGenerator directives in the configuration file for
the batch obfuscator,
and it will start using your class to generate names.
Finally, you can use the basic Hashjava
programming API to write your own obfuscator.
Take a look at the sample
programming example for a starting point.
- How can I incrementally obfuscate
a new set of classes which use a previously obfuscated set of classes?
- This is possible only if the API to your previous set of
classes has not changed. If you have
- the unobfuscated version of the previous classes and
- a "map" of the original to obfuscated names
you can create an obfuscated version of your new classes which will
work with the obfuscated version of the previous classes.
This works by using a combination of the DumpMap and
LoadMap directives in the
batch obfuscator.
- When you obfuscate the original set of classes, dump the original to
new names with the DumpMap directive.
- When you obfuscate the new set of classes, load the file
generated in Step 1 with the LoadMap directive, and
obfuscate it along with the original set of classes.
You can prevent hashjava dumping the original classes with
an appropriate DontDump directive.
Look at the example configuration file for
directions on using these directives.
- How do I select inner classes from the symbol map or in an ExcludeXXX directive?
- Inner classes are named by the JDK 1.1 compiler by appending
the innerclass name to the parent scope, separated by a $.
Anonymous classes, or classes within a method scope have an integer
following the parent scope.
To select an inner class, you must specify the "mangled" name given to
it by the JDK 1.1 compiler. For instance, the inner classes in
class Outer {
class Inner {
class Nested {
}
}
} are identified by Outer$Inner and Outer$Inner$Nested.
Lets say you want to ExcludeClass the class Outer and
all its inner classes. Use this directive in the configuration file
ExcludeClass(ALL, "Outer*");
If you want to obfuscate the inner class Nested, but
ExcludeClass its outer classes, use
ExcludeClass(ALL, "Outer");
ExcludeClass(ALL, "Outer$Inner");
Note: the name for an inner class is derived, even in the obfuscated
code, from the parent scope. For instance, if you have a symbol map
entry like
Outer=X
Outer$Inner=Y
Outer$Inner$Nested=Z
the class names become X, X$Y and X$Y$Z and
the attributes informing the compiler about the relationships between
the inner classes and their parent scope are appropriately updated.
- My Serializable classes don't work
anymore.
- The Java 1.1 serialization mechanism searches for "magic" private
methods named readObject and writeObject in your classes.
Unless you prevent it, hashjava will obfuscate these names and the
serialization won't work properly. Use
the batch
obfuscator and add these two directives in your configuration file
ExcludeMethod(PRIVATE, "*.readObject");
ExcludeMethod(PRIVATE, "*.writeObject");
- I want to send you money for
hashjava.
- Ok, so this really my frequently fantasized question :-)
though "This is great! Why don't you charge money for it?" does come up
on occasion.
If you like it enough you would have paid money for a copy, I'll be
very happy if you give $10 via the online donation center
to the American Red Cross, or
any international charity of your choice.
My plans are to keep hashjava freely available under the LGPL, but
I do not have the resources to offer paid support. I do fix bug reports
as soon as I can, which is generally over a weekend or two.
If you are a tool vendor or software distributor interested in
including hashjava with your product, you can freely do so under
the terms
of the LGPL. Please feel free to contact me for any
information or assistance.
|
| |
Related resources
|
| |
These are some additional resources that
might be interesting.
|
| |
licensing
|
| |
Hashjava is freely distributed with
source code under the
GNU Library General
Public License (LGPL). Code generated by hashjava does not fall
under the same license, and you can use your obfuscated code with
no restrictions.
Under the LGPL, you can also use hashjava as a library and
call its public classes or methods in commercial or non-commercial
applications without disclosing your own source code, provided you
supply the source code to hashjava, and enable anyone modifying
hashjava (without changing its public API) to freely link with your
application. The license has the final word in all cases, but feel
free to contact me for any
clarifications.
|
| |
T o o l s
Obfuscator | Installer | Assembler | Links | Old tools
http://www.sbktech.org/hashjava.html
Revised: Tue Sep 9 22:38:50 1997
Copyright (C) 1996 KB Sriram.
Comments, bug reports:
kbs@sbktech.org
Found something useful?
|